package com.wj.wjpicture.application.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wj.wjpicture.domain.space.service.SpaceDomainService;
import com.wj.wjpicture.infrastructure.exception.BusinessException;
import com.wj.wjpicture.infrastructure.exception.ErrorCode;
import com.wj.wjpicture.infrastructure.exception.ThrowUtils;
import com.wj.wjpicture.interfaces.dto.space.SpaceAddRequest;
import com.wj.wjpicture.interfaces.dto.space.SpaceQueryRequest;
import com.wj.wjpicture.domain.space.entity.Space;
import com.wj.wjpicture.domain.space.entity.SpaceUser;
import com.wj.wjpicture.domain.user.entity.User;
import com.wj.wjpicture.domain.space.valueobject.enums.SpaceLevelEnum;
import com.wj.wjpicture.domain.space.valueobject.enums.SpaceRoleEnum;
import com.wj.wjpicture.domain.space.valueobject.enums.SpaceTypeEnum;
import com.wj.wjpicture.interfaces.vo.space.SpaceVO;
import com.wj.wjpicture.interfaces.vo.user.UserVO;
import com.wj.wjpicture.application.service.SpaceApplicationService;
import com.wj.wjpicture.infrastructure.mapper.SpaceMapper;
import com.wj.wjpicture.application.service.SpaceUserApplicationService;
import com.wj.wjpicture.application.service.UserApplicaitonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* @author 20231001
* @description 针对表【space(空间)】的数据库操作Service实现
* @createDate 2025-07-18 16:07:49
*/
@Service
@Slf4j
public class SpaceApplicationServiceImpl extends ServiceImpl<SpaceMapper, Space>
    implements SpaceApplicationService {
    @Resource
    private UserApplicaitonService userApplicaitonService;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private SpaceUserApplicationService spaceUserApplicationService;
    @Resource
    private SpaceDomainService spaceDomainService;

    // 为了方便部署，注释掉分库分表
//    @Resource
//    @Lazy
//    private DynamicShardingManager dynamicShardingManager;

    // 创建空间
    @Override
    public long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
        // 1.填充默认参数
        // 在此次将实体类和DTO进行转换
        Space space = new Space();
        BeanUtil.copyProperties(spaceAddRequest,space);
        // 默认值
        if(StrUtil.isBlank(spaceAddRequest.getSpaceName())){
            space.setSpaceName("默认空间");
        }
        if(spaceAddRequest.getSpaceLevel() == null){
            space.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
        }
        if(spaceAddRequest.getSpaceType() == null){
            space.setSpaceType(SpaceTypeEnum.PRIVATE.getValue());
        }
        // 填充限额数据
        this.fillSpaceBySpaceLevel(space);

        //2.校验参数
        space.validSpace(true);
        Long userId = loginUser.getId();
        space.setUserId(userId);

        //3.校验权限，非管理员只能创建普通级别的空间
        if(SpaceLevelEnum.COMMON.getValue() != spaceAddRequest.getSpaceLevel() && !loginUser.isAdmin()){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权创建指定级别的空间");
        }

        //4.控制同一用户只能创建一个私有空间
        // 对普通用户进行加锁
        String lock = String.valueOf(userId).intern();
        synchronized (lock){
            Long newSpaceId = transactionTemplate.execute(status -> {
                boolean exists = this.lambdaQuery()
                        .eq(Space::getUserId, userId)
                        .eq(Space::getSpaceType,spaceAddRequest.getSpaceType())
                        .exists();
                ThrowUtils.throwIf(exists, ErrorCode.OPERATION_ERROR, "每个用户每类空间仅能创建一个");
                // 写入数据库
                boolean result = this.save(space);
                ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "创建失败");
                // 如果是团队空间，关联新增团队成员记录
                if(SpaceTypeEnum.TEAM.getValue() == spaceAddRequest.getSpaceType()){
                    SpaceUser spaceUser = new SpaceUser();
                    spaceUser.setSpaceId(space.getId());
                    spaceUser.setUserId(userId);
                    spaceUser.setSpaceRole(SpaceRoleEnum.ADMIN.getValue());
                    result = spaceUserApplicationService.save(spaceUser);
                    ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR,"创建团队成员记录失败");
                }
                // 创建分表,为方便部署，注释掉分库分表
                // dynamicShardingManager.createSpacePictureTable(space);
                return space.getId();
            });
            return Optional.ofNullable(newSpaceId).orElse(-1L);
        }
    }

    // 将查询条件转为QueryWrapper对象
    @Override
    public QueryWrapper<Space> getQueryWrapper(SpaceQueryRequest spaceQueryRequest) {
       return spaceDomainService.getQueryWrapper(spaceQueryRequest);
    }

    // 将Space 转为 SpaceVO 对象
    @Override
    public SpaceVO getSpaceVO(Space space, HttpServletRequest request) {
        // 对象装封装类
        SpaceVO spaceVO = SpaceVO.objToVo(space);
        // 关联查询用户信息
        Long userId = space.getUserId();
        if(userId != null && userId > 0){
            User user = userApplicaitonService.getUserById(userId);
            UserVO userVO = userApplicaitonService.getUserVO(user);
            spaceVO.setUser(userVO);
        }
        return spaceVO;
    }

    // 分页查询
    @Override
    public Page<SpaceVO> getSpaceVOPage(Page<Space> spacePage, HttpServletRequest request) {
        List<Space> spaceList = spacePage.getRecords();
        Page<SpaceVO> spaceVOPage = new Page<>(spacePage.getCurrent(), spacePage.getSize(),spacePage.getTotal());
        if(CollUtil.isEmpty(spaceList)){
            return spaceVOPage;
        }
        // 对象列表 => 封装对象列表
        List<SpaceVO> spaceVOList = spaceList.stream().map(SpaceVO::objToVo).collect(Collectors.toList());
        // 1.关联用户信息
        List<Long> userIdList = spaceList.stream().map(Space::getUserId).collect(Collectors.toList());
        // 通过用户id查询用户并根据id进行分类   userID为key，User为value
        Map<Long, List<User>> userIdUserListMap = userApplicaitonService.listByIds(userIdList).stream().collect(Collectors.groupingBy(User::getId));
        // 2.填充信息(给一个spaceVO对象关联userVO)
        spaceVOList.forEach(spaceVO -> {
            Long userId = spaceVO.getUserId();
            User user = null;
            if(userIdUserListMap.containsKey(userId)){
                user = userIdUserListMap.get(userId).get(0);
            }
            spaceVO.setUser(userApplicaitonService.getUserVO(user));
        });
        spaceVOPage.setRecords(spaceVOList);
        return spaceVOPage;
        /*
        注意，这里我们做了个小优化，不是针对每条数据都查询一次用户，
        而是先获取到要查询的用户 id 列表，只发送一次查询用户表的请求，再将查到的值设置到图片对象中。  这样减小了数据库查询的操作
     */
    }

    // 根据空间级别自动填充限额数据
    @Override
    public void fillSpaceBySpaceLevel(Space space) {
        spaceDomainService.fillSpaceBySpaceLevel(space);
    }

    // 私有空间校验
    /**
     * 空间权限校验
     *
     * @param loginUser
     * @param space
     */
    @Override
    public void checkSpaceAuth(User loginUser, Space space) {
        spaceDomainService.checkSpaceAuth(loginUser,space);
    }

}




